﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection.Emit;

namespace NMapper.Mappings
{
    public class SelectorsMapping<TDatabase, TDatabaseEntity, TOutput, TDbValue, TOutputValue> : 
        ISelectors<TDatabase, TDatabaseEntity, TOutput, TDbValue, TOutputValue>,
        IMapping<TDatabase>
        where TDatabase : IDisposable
    {
        private Expression<Func<MapContext<TDatabase>, TDatabaseEntity, TDbValue>> dbSelector;
        private Expression<Func<TOutput, TOutputValue>> outputSelector;
        private Func<MapContext<TDatabase>, TDatabaseEntity, TDbValue> dbSelectorFunc;
        private Func<TOutput, TOutputValue> outputSelectorFunc;

        public SelectorsMapping(Expression<Func<MapContext<TDatabase>, TDatabaseEntity, TDbValue>> dbSelector, Expression<Func<TOutput, TOutputValue>> outputSelector)
        {
            this.dbSelector = dbSelector;
            this.outputSelector = outputSelector;

            dbSelectorFunc = dbSelector.Compile();
            outputSelectorFunc = outputSelector.Compile();
        }

        public LambdaExpression DbSelectorExpression
        {
            get { return dbSelector; }
        }

        Func<MapContext<TDatabase>, object, object> IDbSelector<TDatabase>.DbSelector
        {
            get { return (mapContext, x) => DbSelector(mapContext, (TDatabaseEntity)x); }
        }

        public Func<MapContext<TDatabase>, TDatabaseEntity, TDbValue> DbSelector
        {
            get { return dbSelectorFunc; }
        }

        public LambdaExpression OutputSelectorExpression
        {
            get { return outputSelector; }
        }

        Func<object, object> IOutputSelector.OutputSelector
        {
            get { return x => OutputSelector((TOutput)x); }
        }

        public Func<TOutput, TOutputValue> OutputSelector
        {
            get { return outputSelectorFunc; }
        }

        public void DefineTransientType(ModuleBuilder module, TypeBuilder type)
        {
        }

        public void DefineTransientInitialization(MapContext<TDatabase> mapContext, Type transientType, List<MemberBinding> initializers, ParameterExpression parameterExpression)
        {
        }

        public void OnTransientInitialized(MapContext<TDatabase> mapContext, Array transient)
        {
        }

        public void MapToOutput(MapContext<TDatabase> mapContext, object transient, object output)
        {
        }

        public void MapToInput(MapContext<TDatabase> mapContext, object output, object input)
        {
        }
    }
}